<?php
namespace Bundle\FireIceBundle;


use Zend\CodeGenerator\Php\PhpFile;
use Zend\CodeGenerator\Php\PhpClass;
use Zend\CodeGenerator\Php\PhpMethod;

class ControllerBuilder
{
    private $_dynamicWorker;

    private $_controllerMeta;

    private $_classMetaDescription;

    public function __construct($dynamicWorker)
    {
        $this->_dynamicWorker = $dynamicWorker;
        $this->_controllerMeta = array();

        $this->_classMetaDescription = array(
            'class' => array(
                'namespaceName' => 'FireIce\Generated\Controllers',
                'name'          => 'IntermediaController',
                'extendedClass' => '\Bundle\FireIceBundle\DynamicController\BaseDynamicController'
            )
        );

    }

    public function getTargetMethod($node, $action, $variables = array())
    {
        //@TODO cache!

        if(!$this->containsMetaFor($node, $action, $variables))
        {
            $nodeId = $node->getId();
            if(!array_key_exists($nodeId , $this->_controllerMeta))
            {
                $this->_controllerMeta[$nodeId] = array(
                    'target' => $node->getController(),
                    'actions' => array()
                );

            }

            if(!array_key_exists($action, $this->_controllerMeta[$nodeId]))
            {
                $this->_controllerMeta[$nodeId]['actions'][$action] = array(
                    'variables' => $variables,
                );
            }
        }

        return $this->createFullPath($node, $action);
    }

    public function createFullPath($node, $action)
    {
        return sprintf('%s::_%d_%s', $this->getFullClassName(), $node->getId(), $action);
    }

    /**
     * Проверка на наличае метаинформации.
     * @param  $node
     * @param  $action
     * @param  $variables
     * @return bool
     */
    public function containsMetaFor($node, $action, $variables)
    {
        return false;
    }

    /**
     * Получение полного имени класса
     * @return string Полное имя класса
     */
    public function getFullClassName()
    {
        return $this->_classMetaDescription['class']['namespaceName'] . '\\' .
                $this->_classMetaDescription['class']['name'];
    }

    /**
     * Получение кода контроллера
     * @param bool $eval
     * @return void
     */
    public function getCode($eval = false)
    {
        $class = new PhpClass($this->_classMetaDescription['class']);

        foreach($this->_controllerMeta as $nodeId => $description)
        {
            foreach($description['actions'] as $action => $attribs)
            {
                $method = new PhpMethod();
                $method->setName('_' . $nodeId . '_' . $action);

                foreach($attribs['variables'] as $var)
                {
                    $method->setParameter(array('name' => $var));
                }

                $body = sprintf('$this->setCurrentNode(%d);', $nodeId);
                $body .= "\n        ";
                $body .= sprintf('return $this->forward(\'%s:%s\', array(', $description['target'], $action);
                foreach($attribs['variables'] as $var)
                {
                    $body .= sprintf('\'%s\' => $%s,', $var, $var);
                }
                $body .= ('), array());');

                //$method->setBody(sprintf('$this->setCurrentNode(%d); return $this->forward(\'%s:%s\', array(), array());',$nodeId, $description['target'], $action));

                $method->setBody($body);

                $class->setMethod($method);
            }
        }

        if($eval)
        {
            return (string) $class;
        }

        $file = new PhpFile();
        $file->setClass($class);

        return (string) $file;
    }


    public function getActionPath($node, $action, $rule)
    {
        if(!$this->isControllerMetaPresent())
        {
            $this->generateControllerMeta();
        }

        if(!$this->containsActionPath($node, $action))
        {
            if(!array_key_exists($node->getId(), $this->_controllerMeta))
            {
                $this->_controllerMeta[$node->getId()] = array();
            }

            $this->_controllerMeta[$node->getId()][$action]
                    = array(
                'node' => $node,
                'method' => sprintf('_%d_%s', $node->getId(), $action),
                'parameters' => $this->processParameters($rule),
                'target' => sprintf('%s::_%d_%s', $this->getFullClassName(), $node->getId(), $action),
            );
        }

        return $this->_controllerMeta[$node->getId()][$action]['target'];
    }

    private function processParameters($rule)
    {
        if(\array_key_exists('params', $rule))
        {
            $result = array();
            foreach($rule['params'] as $param)
            {
                $result[] = array(
                    'name' => $param
                );
            }
            return $result;
        }
        return array();
    }

    private function isControllerMetaPresent()
    {
        return ($this->_controllerMeta != null);
    }

    private function generateControllerMeta()
    {
        $this->_controllerMeta = array();

        

        $this->_classMetaDescription = array(
            'namespaceName' => 'FireIce\Generated',
            'name' => 'IntermediaController',
            'extendedClass' => 'Bundle\FireIceBundle\DynamicController',
        );

    }

    private function containsActionPath($node, $action)
    {
        return array_key_exists($node->getId(), $this->_controllerMeta) &&
                array_key_exists($action, $this->_controllerMeta[$node->getId()]);
    }

    public function getClassCode()
    {
        $phpFile = new PhpFile();

        $phpClass = new PhpClass($this->_classMetaDescription);

        //die(\var_dump($this->_controllerMeta));

        foreach($this->_controllerMeta as $node => $actions)
        {
            foreach($actions as $action => $def)
            {
                $method = new PhpMethod();
                $method->setName($def['method']);

                if(\count($def['parameters']) > 0)
                {
                    //die(\var_dump($def));
                    $method->setParameters($def['parameters']);
                }
                $method->setDocblock(sprintf('Method `%s` for node `%d`', $def['method'], $node));

                $forward = sprintf('$this->forward(\'%s:%s\'', $def['controller'], $action);
//return $this->container->get('kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);

                $body = <<<EOF
           
    // Injection node load
    // @TODO

    // Forwarding to controller
    $forward

EOF
                ;
                $method->setBody($body);
                $phpClass->setMethod($method);
            }
        }


        //$phpClass->setNamespaceName($this->_classMetaDescription['namespace']);

        //$phpClass->setName($this->_classMetaDescription['className']);

        //$phpClass->setExtendedClass()

        $phpFile->setClass($phpClass);



        die(\var_dump((string) $phpFile));
    }
}
